﻿/*
================================================================================
                           单例模式(Singleton Pattern)实现示例
================================================================================

【文件作用】
本文件演示了C++中单例模式的两种经典实现方式：懒汉式和饿汉式单例模式。

【单例模式核心概念】
- 确保一个类只有一个实例
- 提供全局访问点
- 控制实例的创建时机

【两种实现方式对比】
┌─────────────┬──────────────────┬──────────────────────┬─────────────────────┐
│   实现方式   │    创建时机       │      线程安全        │      内存占用       │
├─────────────┼──────────────────┼──────────────────────┼─────────────────────┤
│  懒汉式     │ 首次调用时创建    │ C++11保证线程安全     │ 按需分配，节省内存   │
│  (Lazy)     │                 │ (静态局部变量初始化)  │                    │
├─────────────┼──────────────────┼──────────────────────┼─────────────────────┤
│  饿汉式     │ 程序启动时创建    │ 天然线程安全         │ 程序启动就占用内存   │
│  (Eager)    │                 │ (静态成员在main前初始化) │                    │
└─────────────┴──────────────────┴──────────────────────┴─────────────────────┘

【内存布局】
- 两种单例的实例都存储在数据段(.data段)
- 懒汉式：首次使用时在数据段分配并初始化
- 饿汉式：程序启动时在数据段分配并初始化

【核心技术点】
1. 静态变量的生命周期管理
2. 拷贝构造和赋值运算符的删除(防止违反单例原则)
3. 移动语义的控制
4. 引用返回避免不必要的拷贝
5. C++11的线程安全保证

【使用场景】
- 日志系统
- 配置管理器
- 数据库连接池
- 线程池管理器

【编译环境】
- C++11及以上标准
- 需要支持=delete语法和静态局部变量的线程安全初始化

================================================================================
*/

#define _CRT_SECURE_NO_WARNINGS 1  // 关闭MSVC的安全警告
#include <iostream>
using namespace std;

//================================================================================
//                              懒汉式单例模式
//================================================================================
/**
 * 懒汉式单例 - 延迟初始化版本
 *
 * 【特点】
 * - 首次调用getInstance()时才创建实例
 * - 使用静态局部变量实现
 * - C++11保证静态局部变量初始化的线程安全性
 * - 节省内存，按需创建
 *
 * 【线程安全机制】
 * C++11标准保证：多个线程同时初始化同一个静态局部变量时，
 * 初始化严格只发生一次，其他线程会等待初始化完成。
 */
class LazySingleton {
public:
    /**
     * 获取单例实例的唯一入口
     * @return LazySingleton& 单例对象的引用(不是拷贝！)
     *
     * 【为什么返回引用？】
     * 1. 避免拷贝构造函数调用
     * 2. 确保返回的是同一个对象，而不是副本
     * 3. 符合单例模式"唯一实例"的语义
     */
    static LazySingleton& getInstance() {
        // 静态局部变量 - 关键技术点！
        // 1. 程序运行期间只有一份内存
        // 2. 首次执行到这行时才构造
        // 3. 程序结束时自动析构
        // 4. C++11保证多线程环境下初始化的原子性
        static LazySingleton instance;
        return instance;  // 返回引用，不是拷贝
    }

private:
    /**
     * 私有构造函数 - 防止外部直接创建对象
     * 只能通过getInstance()访问
     */
    LazySingleton() {
        cout << "懒汉式构造" << endl;
    }

    // ========== 禁用拷贝和赋值操作 ==========
    // 这些操作会违反"唯一实例"原则，必须删除

    /**
     * 删除拷贝构造函数
     * 防止: LazySingleton obj2 = obj1; 这种操作
     */
    LazySingleton(const LazySingleton&) = delete;

    /**
     * 删除拷贝赋值运算符
     * 防止: obj1 = obj2; 这种操作
     * 注意：返回引用是为了支持连续赋值，即使被删除也要保持接口一致性
     */
    LazySingleton& operator=(const LazySingleton&) = delete;

    // ========== 禁用移动操作 ==========
    // C++11的移动语义也可能破坏单例，同样需要删除

    /**
     * 删除移动构造函数
     * 防止: LazySingleton obj = std::move(other); 这种操作
     */
    LazySingleton(LazySingleton&&) = delete;

    /**
     * 删除移动赋值运算符
     * 防止: obj1 = std::move(obj2); 这种操作
     */
    LazySingleton& operator=(LazySingleton&&) = delete;
};

//================================================================================
//                              饿汉式单例模式  
//================================================================================
/**
 * 饿汉式单例 - 程序启动时初始化版本
 *
 * 【特点】
 * - 程序启动时(main函数执行前)就创建实例
 * - 使用静态成员变量实现
 * - 天然线程安全(静态成员在多线程环境启动前就初始化完成)
 * - 可能浪费内存(即使不使用也会创建)
 *
 * 【初始化时机】
 * 静态成员变量在程序加载时就完成初始化，早于main()函数执行
 */
class EagerSingleton {
public:
    /**
     * 获取单例实例的唯一入口
     * @return EagerSingleton& 单例对象的引用
     *
     * 【实现原理】
     * 直接返回静态成员变量的引用，不需要判断是否初始化
     * 因为静态成员在程序启动时已经初始化完成
     */
    static EagerSingleton& getInstance() {
        return instance;  // 直接返回已经创建好的静态实例
    }

private:
    /**
     * 私有构造函数 - 防止外部直接创建对象
     * 只有静态成员变量定义时会调用
     */
    EagerSingleton() {
        cout << "饿汉式构造" << endl;
    }

    /**
     * 静态成员变量声明 - 单例实例的存储
     *
     * 【重要】这里只是声明，不是定义！
     * 真正的定义必须在类外进行，即使是private成员也必须类外定义
     * 这是C++静态成员变量的语法规则
     */
    static EagerSingleton instance;

    // ========== 禁用拷贝和赋值操作 ========== 
    // 原理同懒汉式，防止违反单例原则

    EagerSingleton(const EagerSingleton&) = delete;            // 禁用拷贝构造
    EagerSingleton& operator=(const EagerSingleton&) = delete; // 禁用拷贝赋值
    EagerSingleton(EagerSingleton&&) = delete;                 // 禁用移动构造  
    EagerSingleton& operator=(EagerSingleton&&) = delete;      // 禁用移动赋值
};

//================================================================================
//                          静态成员变量定义(类外)
//================================================================================
/**
 * 饿汉式单例的静态成员定义
 *
 * 【关键理解】
 * 1. 这不是"访问"private成员，而是"定义"静态成员
 * 2. 访问权限控制的是"使用"，不是"定义"
 * 3. 静态成员必须在类外定义，这是C++语法要求
 * 4. 定义时会调用构造函数，所以会看到"饿汉式构造"输出
 * 5. 此定义在main()函数执行前就完成
 *
 * 【内存位置】
 * 此实例存储在程序的数据段(.data段)，生命周期为整个程序运行期
 */
EagerSingleton EagerSingleton::instance;  // 静态成员的实际定义和内存分配

//================================================================================
//                              测试代码
//================================================================================
int main() {
    cout << "========== 程序开始执行 ==========" << endl;
    cout << "(注意：饿汉式构造函数在此输出之前就已调用)" << endl;

    // ========== 懒汉式单例测试 ==========
    cout << "\n--- 测试懒汉式单例 ---" << endl;
    cout << "第一次调用getInstance():" << endl;
    LazySingleton& s1 = LazySingleton::getInstance();  // 首次调用，会触发构造
    cout << "第二次调用getInstance():" << endl;
    LazySingleton& s2 = LazySingleton::getInstance();  // 再次调用，不会构造

    // 验证是否为同一个实例
    cout << "s1 address: [" << &s1 << "]" << endl;
    cout << "s2 address: [" << &s2 << "]" << endl;
    cout << "s1和s2是否为同一实例: " << (&s1 == &s2 ? "是" : "否") << endl;

    // ========== 饿汉式单例测试 ==========
    cout << "\n--- 测试饿汉式单例 ---" << endl;
    cout << "调用getInstance()时不会看到构造函数输出(已在程序启动时构造)" << endl;
    EagerSingleton& s3 = EagerSingleton::getInstance();  // 不会触发构造
    EagerSingleton& s4 = EagerSingleton::getInstance();  // 不会触发构造

    // 验证是否为同一个实例
    cout << "s3 address: [" << &s3 << "]" << endl;
    cout << "s4 address: [" << &s4 << "]" << endl;
    cout << "s3和s4是否为同一实例: " << (&s3 == &s4 ? "是" : "否") << endl;

    // ========== 重要说明 ==========
    cout << "\n========== 重要说明 ==========" << endl;
    cout << "1. 必须使用引用接收: Singleton& s = getInstance();" << endl;
    cout << "2. 不能使用值接收: Singleton s = getInstance(); (编译错误)" << endl;
    cout << "3. 拷贝构造已被删除，保证单例唯一性" << endl;
    cout << "4. 懒汉式线程安全由C++11标准保证" << endl;
    cout << "5. 饿汉式天然线程安全(main前初始化完成)" << endl;

    return 0;
}

/*
【预期输出】
饿汉式构造
========== 程序开始执行 ==========
(注意：饿汉式构造函数在此输出之前就已调用)

--- 测试懒汉式单例 ---
第一次调用getInstance():
懒汉式构造
第二次调用getInstance():
s1 address: [0x...]
s2 address: [0x...]  <- 相同地址
s1和s2是否为同一实例: 是

--- 测试饿汉式单例 ---
调用getInstance()时不会看到构造函数输出(已在程序启动时构造)
s3 address: [0x...]
s4 address: [0x...]  <- 相同地址
s3和s4是否为同一实例: 是
*/